/*
 * This class represents an integer based representation of multinomial coefficient
 */
#ifndef _MULTINOMIAL_H
#define _MULTINOMIAL_H

#include<vector>
#include "Combination.cpp"

template<typename T = int, typename container = std::vector<T> > 
class multinomial{
      public:
             multinomial(T k,container l_vec): n(k),m_vec(l_vec){
                 T sum = T(0);
                 typename container::iterator it = l_vec.begin();
                 for(;it!=l_vec.end();++it){
                     sum = sum + *it;
                 }
                 if(sum != k)
                        throw typename multinomial<T,container>::multinomial_exception();
                 result = evaluate(k, l_vec);
             }
             
             T get_result(){return result;}
             T get_n(){return n;}
             T get_lower_terms(){return m_vec;}
             
             class multinomial_exception: public std::exception{
                    virtual const char* what() const throw(){
                     return "Error in multinomial: the lower sum must equal n.";
                 }
             };
             
      private:
              T result;
              T n;
              container m_vec;
              
              T evaluate(T k, container l_vec);
};

template<typename T, typename container>
T multinomial<T,container>::evaluate(T k, container l_vec){
    if(l_vec.size()==1){
        if(l_vec[0] == k) return T(1);
        return T(0);
    }
    T res = T(1);
    T temp = k;
    for(int i = 0; i<l_vec.size();++i){
            if(l_vec[i] < T(0)) return T(0);
            res = res * combination<T>(temp,l_vec[i]).get_result();
            temp = temp - l_vec[i];
    }
    return res;
}

#endif
